class IUP_MENU
-- Creates a menu element, which groups 3 types of interface elements: item, 
-- submenu and separator. Any other interface element defined inside a menu 
-- will be an error.
--
-- A menu can be a menu bar of a dialog, defined by the dialog's MENU 
-- attribute, or a popup menu.
--
-- A popup menu is displayed for the user using the popup function (usually on 
-- the mouse position) and disappears when an item is selected.
--
-- destroy should be called only for popup menus. Menu bars associated with 
-- dialogs are automatically destroyed when the dialog is destroyed. But if you 
-- change the menu of a dialog for another menu, the previous one should be 
-- destroyed destroy. If you replace a menu bar of a dialog, the previous menu 
-- is unmapped.
--
-- Any item inside a menu bar can retrieve attributes from the dialog using 
-- get_attribute. It is not necessary to call get_dialog.
--
-- The menu can be created with no elements and be dynamic filled using append 
-- or insert. 

inherit
	IUP_WIDGET
		redefine
			execute_map,
			execute_unmap,
			execute_destroy,
			execute_open,
			execute_menuclose
		end
	IUP_WIDGET_BGCOLOR
	IUP_WIDGET_POPUP
	IUP_WIDGET_NAME

create {ANY}
   menu_empty,
	menu

feature {ANY}

	menu_empty
	   -- Create an empty menu
		local
			p, a_menu: POINTER
		do
			a_menu := int_empty_menu (p)
			set_widget(a_menu)
		end
		
	menu (col: ARRAY[IUP_MENU_ELEMENT])
	   -- Create a new menu containing the list of item
		local
         i: INTEGER; arg: ARRAY[POINTER]; s: IUP_WIDGET; a_menu: POINTER
		do
			i := col.count

			create arg.make_filled(default_pointer, 1, i + 1)
			i := 0
			
			across
			   col as ic
         loop
            i := i + 1
            s := ic.item
            arg.put(s.widget, i)
         end

			a_menu := int_menu (get_pointer(arg.to_c))
			set_widget(a_menu)
		end

	-- Attributes

	set_radio (state: BOOLEAN)
		-- (non inheritable): enables the automatic toggle of one child item. 
		-- When a child item is selected the other item is automatically 
		-- deselected. The menu acts like a IUP_RADIO for its children. Submenus 
		-- and their children are not affected.
		do
			iup_open.set_attribute(Current, "RADIO", boolean_to_yesno(state))
		end

	-- Commands to handle heirarchy
	
	append (new_child: IUP_WIDGET): detachable IUP_WIDGET
		-- Inserts an interface element at the end of the container, after 
		-- the last element of the container. Valid for any element that
		-- contains other elements like dialog, frame, hbox, vbox, zbox or menu.
		-- Returns: the actual parent if the interface element was 
		-- successfully inserted. Otherwise returns Void.
		do
			Result := iup_open.iup_append(Current, new_child)
		end

   insert (ref_child: IUP_WIDGET; new_child: IUP_WIDGET): detachable IUP_WIDGET
		-- Inserts an interface element before another child of the 
		-- container. Valid for any element that contains other elements 
		-- like dialog, frame, hbox, vbox, zbox, menu, etc.
		-- Returns: the actual parent if the interface element was 
		-- successfully inserted. Otherwise returns NULL
		do
			Result := iup_open.iup_insert(Current, ref_child, new_child)
		end

	-- PopUp
	popup_mouse_position: STRING
		-- Shows the menu at mouse position and restricts user interaction only 
		-- to the specified  element. If there was an error returns IUP_ERROR.
		do
			Result := iup_open.popup_predefined_xy(Current, "IUP_MOUSEPOS", "IUP_MOUSEPOS")
		end

	set_popup_alignment (horizontal: STRING; vertical: STRING)
		-- alignment of the popup menu relative to the given point. Where horizontal 
		-- can be: ALEFT, ACENTER or ARIGHT; and vertical can be ATOP, ACENTER or 
		-- ABOTTOM. Default: ALEFT:ATOP.
		require
			is_valid_alignment(horizontal, vertical)
		local
			str: STRING
		do
			create str.make_from_string(horizontal)
	      str.append_string(":")
 	      str.append_string(vertical)
	
			iup_open.set_attribute(Current, "POPUPALIGN", str)
		end

	-- Callbacks

	-- Common
	set_cb_map (act: detachable FUNCTION[TUPLE[IUP_MENU], STRING])
		-- Called right after an element is mapped and its attributes updated.
		local
			operation: INTEGER
		do
			cb_map := act
			
			if cb_map /= Void then
				operation := 1
			else
				operation := 0
			end
						
			iup_open.set_callback (Current, "MAP_CB", "NONEEDED", operation)
		end

	set_cb_unmap (act: detachable FUNCTION[TUPLE[IUP_MENU], STRING])
		-- Called right before an element is unmapped.
		local
			operation: INTEGER
		do
			cb_unmap := act

			if cb_unmap /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "UNMAP_CB", "NONEEDED", operation)
		end

	set_cb_destroy (act: detachable FUNCTION[TUPLE[IUP_MENU], STRING])
		-- Called right before an element is destroyed.
		local
			operation: INTEGER
		do
			cb_destroy := act

			if cb_destroy /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "DESTROY_CB", "NONEEDED", operation)
		end

	set_cb_open (act: detachable FUNCTION[TUPLE[IUP_MENU], STRING])
		-- Called just before the menu is opened.
		local
			operation: INTEGER
		do
			cb_open := act

			if cb_open /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "OPEN_CB", "NONEEDED", operation)
		end

	set_cb_menu_close (act: detachable FUNCTION[TUPLE[IUP_MENU], STRING])
		-- Called just after the menu is closed.
		local
			operation: INTEGER
		do
			cb_menuclose := act

			if cb_menuclose /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "MENUCLOSE_CB", "NONEEDED", operation)
		end

	-- Validations

	is_valid_alignment (horizontal, vertical: STRING): BOOLEAN
		local
			h, v: BOOLEAN
		do
			if horizontal.is_equal("ALEFT") or
				horizontal.is_equal("ACENTER") or
				horizontal.is_equal("ARIGHT") then
				h := True
			else
				h := False
			end

			if vertical.is_equal("ATOP") or
				vertical.is_equal("ACENTER") or
				vertical.is_equal("ABOTTOM") then
				v := True
			else
				v := False
			end

			if h and v then
				Result := True
			else
				Result := False
			end
		end

feature {IUP}

	-- Common callbacks
	
	execute_map: STRING
		do
			if attached cb_map as int_cb then
				Result := int_cb.item([Current])
			else
				Result := "IUP_DEFAULT"
			end
		end

	execute_unmap: STRING
		do
			if attached cb_unmap as int_cb then
				Result := int_cb.item([Current])
			else
				Result := "IUP_DEFAULT"
			end
		end

	execute_destroy: STRING
		do
			if attached cb_destroy as int_cb then
				Result := int_cb.item([Current])
			else
				Result := "IUP_DEFAULT"
			end
		end

	-- Extra
	execute_open: STRING
		do
			if attached cb_open as int_cb then
				Result := int_cb.item([Current])
			else
				Result := "IUP_DEFAULT"
			end
		end

	execute_menuclose: STRING
		do
			if attached cb_menuclose as int_cb then
				Result := int_cb.item([Current])
			else
				Result := "IUP_DEFAULT"
			end
		end

feature {NONE}

	-- For callbacks
	
	cb_map: detachable FUNCTION[TUPLE[IUP_MENU], STRING]
	cb_unmap: detachable FUNCTION[TUPLE[IUP_MENU], STRING]
	cb_destroy: detachable FUNCTION[TUPLE[IUP_MENU], STRING]

	cb_open: detachable FUNCTION[TUPLE[IUP_MENU], STRING]
	cb_menuclose: detachable FUNCTION[TUPLE[IUP_MENU], STRING]

	-- Internals
	
	int_empty_menu (list: POINTER): POINTER
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"return IupMenu ($list);"
      end
	
   int_menu (list: POINTER): POINTER
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"return IupMenuv ($list)"
      end

end

-- The MIT License (MIT)

-- Copyright (c) 2016, 2017, 2019, 2020, 2021 by German A. Arias

-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in 
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
